import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:xindong/common/xindong_api_path.dart';
import 'package:xindong/common/xindong_app_info.dart';
import 'package:xindong/common/xindong_all.dart';
import 'package:xindong/common/xindong_methods.dart';
import 'package:xindong/extension/extension_string.dart';
import 'package:xindong/manager/network/xindong_interceptors.dart';
import 'package:xindong/manager/network/xindong_response.dart';
import 'package:xindong/manager/xindong_user_controller.dart';
import 'package:xindong/routes/call/controller/xindong_call_handle.dart';

// 域名
const String kReleaseUrl = "https://app.zhitgx.cn/";
const String kDebugUrl = "https://app.zhitgx.cn/";

// 请求方式
class XinDongHttpMethod {
  static const get = 'GET';
  static const post = 'POST';
}

// 错误码
class XinDongServerStatus {
  static const success = 200; // 成功
  static const unregistered = 300; // 未注册，账号不存在
  static const zhuXiao = 302; // 未注册，已注销重新注册
  static const userError = 400; // "请重新登录"、"验证码错误，请重新发送"
  static const accountClose = 402; // 默认成功
  static const codeReuse = 1106; // 验证码可重复使用，用回上一次的验证码
  static const poor = 201; // 不够钱

  static const interceptCancelled = -666; // 取消 - 拦截重复请求
}

class XinDongNetworking {
  // 属性和方法
  late Dio dio;

  // URL
  String get baseUrl {
    return XinDongAll.instance.isRelease ? kReleaseUrl : kDebugUrl;
  }

  // URL
  String get fileUrl => baseUrl;

  // web
  String get agreementUrl => "${baseUrl}api/page/index?id=2";

  String get privacyUrl => "${baseUrl}api/page/index?id=3";

  String get appUrl => "${baseUrl}api/page/index?id=6";

  String get helpUrl => "${baseUrl}api/page/index?id=10";

  String get withdrawUrl => "${baseUrl}api/page/index?id=11";

  String get huiYuanUrl => "${baseUrl}api/page/index?id=26";

  String get inviteUrl => "${baseUrl}api/page/index?id=7";

  String get downloadUrl => "${baseUrl}invitation/${XinDongUserController.to.loginId}";

  // 不提示名单，想提示的自己提示
  List doNotToastList = [
    "/api/login/setOnline",
    "/api/member/config",
    "/api/user/updateTags",
    XinDongCallHandle().callTime,
  ];

  // 不提示名单，成功也不提示
  List doNotToastSuccessList = [
    XinDongApi.getCustomer,
    XinDongApi.userSig,
    XinDongApi.messageCount,
    "/api/grade/isReBuy",
    "/api/member/getOnLinePay",
    "/apis/index.php/home/user/vipdymanic",
  ];

  // 请求头
  Map<String, dynamic> httpHeaders() {
    return {
      // "lat": XinDongGlobal.instance.currentLocation.latitude,
      // "lng": XinDongGlobal.instance.currentLocation.longitude,
      // "token": XinDongUserController.to.serverToken,
    };
  }

  // 请求参数
  Map<String, dynamic> httpParameters() {
    return {
      "user_id": XinDongUserController.to.loginId,
      // "lng": "116.39722800",
    };
  }

  // 发起请求-返回 ResponseObject
  // path 接口
  // method 请求方式
  // headers 请求头数据
  // parameters 请求参数
  Future<NetworkResponse> request(String path,
      {String method = XinDongHttpMethod.get, Map? headers, Map? parameters, bool addUserId = true}) async {
    try {
      // Map类型也要转一下，避免类型不匹配
      Map<String, dynamic> newHeaders = httpHeaders()..addAll(Map.from(headers ?? {}));
      Map<String, dynamic> newParameters = {};
      if (addUserId) {
        newParameters.addAll({"user_id": XinDongUserController.to.loginId});
      }
      newParameters.addAll(Map.from(parameters ?? {}));

      // 发起请求
      Response? response;
      switch (method) {
        case XinDongHttpMethod.get:
          {
            dio.options.headers = newHeaders;
            response = await dio.get<dynamic>(path, queryParameters: newParameters);
          }
          break;
        case XinDongHttpMethod.post:
          {
            // post数据要放data，不然编码有问题
            dio.options.headers = newHeaders;
            response = await dio.post<dynamic>(path, data: newParameters);
          }
          break;
        default:
          break;
      }
      // 请求结果
      return _handleWithResponse(response);
    } catch (e) {
      return _handleWithException(e);
    }
  }

  // 上传单个文件
  Future<String?> uploadWangYiFile({required String filePath}) async {
    try {
      final formData = FormData.fromMap({
        'image': await MultipartFile.fromFile(filePath, filename: filePath.pathFileName),
        "thumb": 0,
        "water": 0,
        "user_id": XinDongUserController.to.loginId,
      });
      final response =
          await dio.post(XinDongApi.imageUploadWangYi, data: formData, onSendProgress: (int sent, int total) {
        mDebugPrint('进度$sent $total');
      });
      final object = _handleWithResponse(response);
      if (object.code == XinDongServerStatus.success) {
        return object.data["img"];
      }
      return null;
    } catch (e) {
      _handleWithException(e);
      return null;
    }
  }

  // 上传单个文件
  Future<String?> uploadVideo({required String filePath}) async {
    try {
      final formData = FormData.fromMap({
        'video': await MultipartFile.fromFile(filePath, filename: filePath.pathFileName),
      });
      final response = await dio.post(XinDongApi.videoUpload, data: formData, onSendProgress: (int sent, int total) {
        mDebugPrint('进度$sent $total');
      });
      final object = _handleWithResponse(response);
      if (object.code == XinDongServerStatus.success) {
        return object.data["image"];
      }
      return null;
    } catch (e) {
      _handleWithException(e);
      return null;
    }
  }

  // 上传单个文件
  Future<String?> uploadFile({required String filePath}) async {
    try {
      final formData = FormData.fromMap({
        'image': await MultipartFile.fromFile(filePath, filename: filePath.pathFileName),
        "thumb": 0,
        "water": 0,
      });
      final response = await dio.post(XinDongApi.imageUpload, data: formData, onSendProgress: (int sent, int total) {
        mDebugPrint('进度$sent $total');
      });
      final object = _handleWithResponse(response);
      if (object.code == XinDongServerStatus.success) {
        return object.data["image"];
      }
      return null;
    } catch (e) {
      _handleWithException(e);
      return null;
    }
  }

  // 上传多个文件
  Future<String?> uploadFiles({required List<String> filePaths}) async {
    try {
      List<MultipartFile> list = [];
      for (int i = 0; i < filePaths.length; i++) {
        list.add(await MultipartFile.fromFile(filePaths[i], filename: filePaths[i].pathFileName));
      }
      final formData = FormData.fromMap({'image[]': list, "thumb": 1, "water": 1});
      final response = await dio.post(XinDongApi.imagesUpload, data: formData, onSendProgress: (int sent, int total) {
        mDebugPrint('进度$sent $total');
      });
      final object = _handleWithResponse(response);
      if (object.code == XinDongServerStatus.success) {
        return object.data["images"]; // 字符串，用英文逗号隔开
        // return urls.stringToList();
      }
      return null;
    } catch (e) {
      _handleWithException(e);
      return null;
    }
  }

  // 实例化Dio
  void setupDio() {
    print("$baseUrl ${XinDongAppDeviceInfo.instance.showAppVersion}");
    final BaseOptions options = BaseOptions(
      baseUrl: baseUrl,
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 15),
      responseType: ResponseType.json,
      contentType: Headers.formUrlEncodedContentType, // 使用application/x-www-form-urlencoded编码
    );
    dio = Dio(options);
    dio.interceptors.add(NetworkInterceptors(dio));
    dio.httpClientAdapter = IOHttpClientAdapter(
      createHttpClient: () {
        final client = HttpClient();
        // client.findProxy = (uri) {
        //   // 将请求代理至 localhost:8888。
        //   // 请注意，代理会在你正在运行应用的设备上生效，而不是在宿主平台生效。
        //   return 'PROXY localhost:8888';
        // };
        return client;
      },
    );
  }

  // 单例
  // 静态变量_instance，存储唯一对象
  static XinDongNetworking? _instance;

  // 工厂方法构造函数
  factory XinDongNetworking() => _getInstance();

  // instance的getter方法，.instance获取对象
  static XinDongNetworking get instance => _getInstance();

  // 获取对象
  static XinDongNetworking _getInstance() {
    _instance ??= XinDongNetworking._internal();
    return _instance!;
  }

  // 私有的自定义命名式构造方法，通过它实现一个类;
  // 子类不能继承internal
  // 不是关键字，可定义其他名字
  XinDongNetworking._internal() {
    //初始化(设置一些默认的)...
    setupDio();
  }
}

extension NetworkingMethods on XinDongNetworking {
  // 生成请求记录名称
  String generateRecordName(RequestOptions options) {
    if (options.method.toUpperCase() == XinDongHttpMethod.post) {
      return options.uri.toString() + options.data.toString();
    }
    return options.uri.toString();
  }

  // 转换错误类型
  OSError convertError(DioException exception) {
    int? errorCode;
    String? errorMessage;
    switch (exception.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        break;
      case DioExceptionType.connectionError:
        {
          errorCode = exception.response?.statusCode;
          errorMessage = "网络错误，请稍后重试";
        }
        break;
      case DioExceptionType.badResponse:
        {
          errorCode = exception.response?.statusCode;
          errorMessage = exception.message;
        }
        break;
      case DioExceptionType.cancel:
        {
          errorCode = XinDongServerStatus.interceptCancelled;
          errorMessage = "操作取消";
        }
        break;
      default:
        {
          // other
          if (exception.error is SocketException) {
            SocketException tempException = exception.error as SocketException;
            errorCode = tempException.osError?.errorCode;
            errorMessage = tempException.osError?.message;
          }
        }
        break;
    }
    return OSError(errorMessage ?? "", errorCode ?? -1);
  }
}

extension NetworkingHandle on XinDongNetworking {
  // 处理异常结果
  NetworkResponse _handleWithException(e) {
    // 异常就重新实例化一下Dio，不知道能不能解决nodename nor servname provided, or not known问题
    setupDio();
    mCatchPrint(e.toString());
    if (e is DioException) {
      OSError error = convertError(e);
      mDebugPrint('处理失败 ${error.errorCode} ${error.message} ${e.requestOptions.uri.toString()}');
      return NetworkResponse(code: error.errorCode, msg: error.message);
    }
    return NetworkResponse(code: XinDongServerStatus.interceptCancelled, msg: e.toString());
  }

  // 处理响应结果
  NetworkResponse _handleWithResponse(Response? response) {
    if (response == null) {
      return NetworkResponse(code: XinDongServerStatus.interceptCancelled, msg: "请求方式不是get、post");
    }
    if (response.statusCode != 200) {
      return NetworkResponse(code: response.statusCode!, msg: response.statusMessage!);
    }
    // 神奇，有部分接口返回的是html，不是json
    if (response.data is String) {
      response.data = json.decode(response.data);
    }
    // httpCode == 200
    final object = NetworkResponse.fromJson(response.data);

    switch (object.code) {
      // 成功
      case XinDongServerStatus.success:
        break;
      case XinDongServerStatus.userError: // 未登陆
      case XinDongServerStatus.accountClose: // 封号
        {}
        break;
    }
    if (object.msg == "请重新登录") {
      XinDongUserController.to.passiveLogout();
    }
    // 不提示清单，排除success
    bool isExistSuccessList = doNotToastSuccessList.any((element) => element == response.realUri.path);
    if (!isExistSuccessList) {
      bool isExist = doNotToastList.any((element) => element == response.realUri.path);
      if (isExist == false && object.msg != null && (object.msg != "success") && (object.msg != "升级会员才能发表评论")) {
        showToast(object.msg);
      }
    }
    return object;
  }
}
